/**
  ******************************************************************************
  * @file    kfifo.c
  * @author  vincent
  * @version V3.5.0
  * @date    2017/09/07
  * @brief   This file provides main functions.
  ******************************************************************************
  * @attention
  *
  * 
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
/*stander include*/
#include "string.h"

/*user include*/
#include "kfifo.h"


#if(USE_FREERTOS == 1)
/*FreeRTOS include*/
	#include "FreeRTOS.h"
	#include "task.h"
#endif
/* prama define discrible -----------------------------------------------------*/
#if(USE_FREERTOS == 1)
  #define prvKfifoMalloc    pvPortMalloc 
  #define prvKfifoFree      vPortFree
#else
  #define prvKfifoMalloc    malloc 
  #define prvKfifoFree      free	
#endif

#define min(a, b)				(((a) < (b)) ? (a) : (b))

/* strcuct  discrible --------------------------------------------------------*/

/* prama  discrible ---------------------------------------------------------*/


/* private fucntion  declaration --------------------------------------------*/
kfifo_t *kfifo_alloc(unsigned int size);
void kfifo_free(kfifo_t *kfifo);
unsigned int kfifo_leftdata_len(kfifo_t *kfifo);
unsigned int kfifo_put(kfifo_t *fifo, unsigned char *buffer, unsigned int len);
unsigned int kfifo_get(kfifo_t *fifo, unsigned char *buffer, unsigned int len); 
unsigned int roundup_pow_of_two(unsigned int date_roundup_pow_of_two );

/******************************************************************************
* @Function:  kfifo_buf_t* usrKfifo_buf_alloc(unsigned int size)
* @Discrible:  分配kfifo_buf_t 内存空间，分别分配kfifo_buf_t，和kfifo_buf_t->kfifo_t
* @Param:  size智能是2的次幂
* @Return:   
* @Others:  
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
kfifo_buf_t* usrKfifo_buf_alloc(unsigned int size)
{
	kfifo_buf_t *kfifo_buf = NULL;
	kfifo_t *kfifo = NULL;
		
	kfifo_buf =(kfifo_buf_t *)prvKfifoMalloc(sizeof (kfifo_buf_t));
	
	kfifo = kfifo_alloc(size);
	
	/*如果kfifo分派失败，则将kfifo_buf也释放*/
	if(kfifo == NULL)
	{
		prvKfifoFree(kfifo_buf);
		return kfifo_buf;
	}
  
	kfifo_buf->kfifo = kfifo; 
	kfifo_buf->Read = kfifo_get; 
	kfifo_buf->Write = kfifo_put;
	kfifo_buf->LetfDataLen = kfifo_leftdata_len;
	
	/*释放临时控件*/
	prvKfifoFree(kfifo_buf);
	
	return kfifo_buf;
}


/******************************************************************************
* @Function:  void usrKfifo_buf_free(kfifo_buf_t* kfifo_buf)
* @Discrible:  释放kfifo_buf_t控件
* @Param:  
* @Return:   
* @Others:  
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
void usrKfifo_buf_free(kfifo_buf_t* kfifo_buf)
{
	 if (kfifo_buf != NULL)
	{
		if (kfifo_buf->kfifo != NULL)
		{
			kfifo_free(kfifo_buf->kfifo);
		}		
		prvKfifoFree(kfifo_buf );
		kfifo_buf = NULL;
	}
}	

/* private fucntion  discrible -----------------------------------------------*/
/******************************************************************************
* @Function:  kfifo_t  *kfifo_alloc(unsigned int size) 
* @Discrible:  分配Kfifo 内存空间，分别分配kfifo_t，和kfifo_t->buff
* @Param:  
* @Return:   
* @Others:  size的值只能取2的次幂数，这是为了后面出列入列指针移动溢出的处理，同时也是
* 为解决不使用互锁而付出的代价
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
kfifo_t  *kfifo_alloc(unsigned int size) 
{   
    unsigned char *buffer;	
    kfifo_t *ret;
	
	ret=(kfifo_t *)prvKfifoMalloc(sizeof (kfifo_t));
    /*  
     * round up to the next power of 2, since our 'let the indices  
     * wrap' tachnique works only in this case.  
		* 如果size 是2的 次幂圆整，则 size & (size - 1)  =0
     */
  
    if (size & (size - 1)) 
	{   
	    //BUG_ON(size > 0x80000000);  
	    /*如果你要申请的buffer 不是 2的 次幂圆整，就要把 size 变成 2的次幂圆整 ，方便下面计算*/
        size = roundup_pow_of_two(size);
    }
		
    buffer = (unsigned char*) prvKfifoMalloc(size);
	
    /*如果返回的值为NULL，这说明分配内存失败*/ 	
    if (!buffer) 
	{		
        return 0UL;
	}
  
	//    ret = kfifo_init(buffer, size, lock);   
	
	ret->buffer=buffer;
	ret->size  =size;
	ret->in  = 0;
	ret->out = 0;
	
    /*如果ret的值为NULL，这说明分配内存失败*/	
    if (!ret) 
	{
		/*释放之前分配的 内存空间*/
        prvKfifoFree(buffer);
	}
    return ret;	
}

/******************************************************************************
* @Function:  void kfifo_free(kfifo_t *kfifo)
* @Discrible:  释放缓冲区,分配内存的时候分别分配了kfifo_t，
*              和kfifo_t->buff,释放的时候也要释放两次
* @Param:  
* @Return:   
* @Others: 
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
void kfifo_free(kfifo_t *kfifo)
{
	if (kfifo != NULL)
	{
		if (kfifo->buffer != NULL)
		{
			prvKfifoFree(kfifo->buffer);
			kfifo->buffer = NULL;
		}	
		
		prvKfifoFree(kfifo);
		kfifo = NULL;
	}
}
/******************************************************************************
* @Function:  unsigned int kfifo_leftdata_len(kfifo_t *kfifo)
* @Discrible:  获取缓冲区剩余数据的长度
* @Param:  
* @Return:   
* @Others: 
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
unsigned int kfifo_leftdata_len(kfifo_t *kfifo)
{	
    return (kfifo->in - kfifo->out);
}
/******************************************************************************
* @Function:  unsigned int kfifo_put(kfifo_t *fifo, unsigned char *buffer, unsigned int len) 
* @Discrible:  向缓冲区中存放数据
* @Param:  
* @Return:   
* @Others: 
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
unsigned int kfifo_put(kfifo_t *fifo, unsigned char *buffer, unsigned int len)   
{
    unsigned int L;
	
	/*环形缓冲区的剩余容量为fifo->size - fifo->in + fifo->out，让写入的长度取len和剩余容量中较小的，避免写越界；*/
    len = min( len , fifo->size - fifo->in + fifo->out );
  
    /*  
     * Ensure that we sample the fifo->out index -before- we  
     * start putting bytes into the kfifo.  
     */   
				
	//    smp_mb(); /*多处理器 处理内存 的 屏障，STM32不需要这个*/
  
    /* first put the data starting from fifo->in to buffer end */
	/* 首先将数据从fifo.in 所在的位置开始写，写之前，首先要看一下fifo->in到 buffer 末尾的大小 是不是 比 len 大*/

	/*
	 * 前面讲到fifo->size已经2的次幂圆整，主要是方便这里计算，提升效率
	 * 在对10进行求余的时候，我们发现，余数总是整数中的个位上的数字，而不用管其他位是什么；
	 * 所以,kfifo->in % kfifo->size 可以转化为 kfifo->in & (kfifo->size – 1)，效率会提升
	 * 所以fifo->size - (fifo->in & (fifo->size - L)) 即位 fifo->in 到 buffer末尾所剩余的长度，
	 * L取len和剩余长度的最小值，即为需要拷贝L 字节到fifo->buffer + fifo->in的位置上。
	 */ 
    L = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
	
    memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, L);   
  
    /* then put the rest (if any) at the beginning of the buffer */ 

    memcpy(fifo->buffer, buffer + L, len - L);
  
    /*  
     * Ensure that we add the bytes to the kfifo -before-  
     * we update the fifo->in index.  
     */   
  
      // smp_wmb();   /*多处理器 处理内存 的 屏障，STM32不需要这个*/	

	/* 
	 * 注意这里 只是用了 fifo->in +=  len而未取模，
	 * 这就是kfifo的设计精妙之处，这里用到了unsigned int的溢出性质，
	 * 当in 持续增加到溢出时又会被置为0，这样就节省了每次in向前增加都要取模的性能，
	 */
  
    fifo->in += len; 
		
  	/*返回值 代表  写入数据的个数 ，这样 就可以根据返回值 判断缓冲区是否写满*/
    return len;   
}  

/******************************************************************************
* @Function:  unsigned int kfifo_get(kfifo_t *fifo, unsigned char *buffer, unsigned int len) 
* @Discrible: 从缓冲区中取数据
* @Param:  
* @Return:   
* @Others: 
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
unsigned int kfifo_get(kfifo_t *fifo, unsigned char *buffer, unsigned int len)   
{
    unsigned int L;   
  
    len = min(len, fifo->in - fifo->out);   
  
    /*  
     * Ensure that we sample the fifo->in index -before- we  
     * start removing bytes from the kfifo.  
     */   
  
    //smp_rmb();    /*多处理器 处理内存 的 屏障，STM32不需要这个*/
  
    /* first get the data from fifo->out until the end of the buffer */   
    L = min(len, fifo->size - (fifo->out & (fifo->size - 1)));   
    memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), L);   
  
    /* then get the rest (if any) from the beginning of the buffer */   
    memcpy(buffer + L, fifo->buffer, len - L);   
  
    /*  
     * Ensure that we remove the bytes from the kfifo -before-  
     * we update the fifo->out index.  
     */   
  
    //smp_mb();   /*多处理器 处理内存 的 屏障，STM32不需要这个*/
			
	/*
     * 注意这里 只是用了 fifo->out +=  len 也未取模运算，
	 * 同样unsigned int的溢出性质，当out 持续增加到溢出时又会被置为0，
	 * 如果in先溢出，出现 in  < out 的情况，那么 in – out 为负数（又将溢出），
	 * in – out 的值还是为buffer中数据的长度。
	 */

    fifo->out += len;
  
    return len;  
}


///******************************************************************************
//* @Function:  kfifo_t  *kfifo_alloc(unsigned int size) 
//* @Discrible:  分配Kfifo 内存空间
//* @Param:  
//* @Return:   
//* @Others: 
//******************************************************************************
//* @Recode    date       version	        author             modify 
//*          ------------------------------------------------------------------
//*          20170909      V1.0          VINCENT            Create
//* 
//*******************************************************************************/
//uint32_t ring_buffer_len(const struct ring_buffer *ring_buf)
//{
//    uint32_t len = 0;
//    pthread_mutex_lock(ring_buf->f_lock);
//    len = __ring_buffer_len(ring_buf);
//    pthread_mutex_unlock(ring_buf->f_lock);
//    return len;
//}


///******************************************************************************
//* @Function:  kfifo_t  *kfifo_alloc(unsigned int size) 
//* @Discrible:  分配Kfifo 内存空间
//* @Param:  
//* @Return:   
//* @Others: 
//******************************************************************************
//* @Recode    date       version	        author             modify 
//*          ------------------------------------------------------------------
//*          20170909      V1.0          VINCENT            Create
//* 
//*******************************************************************************/
//uint32_t ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, uint32_t size)
//{
//    uint32_t ret;
//    pthread_mutex_lock(ring_buf->f_lock);
//    ret = __ring_buffer_get(ring_buf, buffer, size);
//    //buffer中没有数据
//    if (ring_buf->in == ring_buf->out)
//    ring_buf->in = ring_buf->out = 0;
//    pthread_mutex_unlock(ring_buf->f_lock);
//    return ret;
//}


///******************************************************************************
//* @Function:  kfifo_t  *kfifo_alloc(unsigned int size) 
//* @Discrible:  分配Kfifo 内存空间
//* @Param:  
//* @Return:   
//* @Others: 
//******************************************************************************
//* @Recode    date       version	        author             modify 
//*          ------------------------------------------------------------------
//*          20170909      V1.0          VINCENT            Create
//* 
//*******************************************************************************/
//uint32_t ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)
//{
//    uint32_t ret;
//    pthread_mutex_lock(ring_buf->f_lock);
//    ret = __ring_buffer_put(ring_buf, buffer, size);
//    pthread_mutex_unlock(ring_buf->f_lock);
//    return ret;
//}


/******************************************************************************
* @Function:  unsigned int roundup_pow_of_two(unsigned int date_roundup_pow_of_two )
* @Discrible: 找出最接近 最大2的指数次幂
* @Param:  
* @Return:   
* @Others:
* 这里采用 STM32 硬件提供的计算前导零指令 CLZ
* 举个例子，假如变量date_roundup_pow_of_two 0x09
*（二进制为：0000 0000 0000 0000 0000 0000 0000 1001）, 即bit3和bit0为1
* 则__clz( (date_roundup_pow_of_two)的值为28,即最高位1 前面有28个0,32-28 =3 代表最高位1 的 位置
* 31UL 表示 无符号 int 数字 31，否则默认为 有符号 int 数字 31
* 这里参考  FreeRTOS 的 寻找高级优先级任务 的写法，详细解释到朱工博客
* 博客地址: http://blog.csdn.net/zhzht19861011/article/details/51418383
*
******************************************************************************
* @Recode    date       version	        author             modify 
*          ------------------------------------------------------------------
*          20170909      V1.0          VINCENT            Create
* 
*******************************************************************************/
unsigned int roundup_pow_of_two(unsigned int date_roundup_pow_of_two )
{				
	return ( 1UL << ( 32UL - ( unsigned int ) __clz( (date_roundup_pow_of_two) ) ) );
}

/************************ (C) END OF FILE ************************************/





